package timetasklogic

import (
	"common/comOss"
	"common/dao/model"
	"common/utils"
	"context"
	"database/sql"
	"fmt"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"gorm.io/gorm"
	"os"
	"strings"
	"time"
	"timeTask/internal/svc"
	"timeTask/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type TaskMysqlLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewTaskMysqlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TaskMysqlLogic {
	return &TaskMysqlLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *TaskMysqlLogic) TaskMysql(in *pb.Emp) (*pb.Emp, error) {
	// todo: add your logic here and delete this line

	//fmt.Println("1231231")
	uuid := utils.GetUuid()

	err := exportAllTablesToSQL(l.svcCtx.DB, uuid)
	if err != nil {
		return nil, err
	}

	response, err := comOss.GetOssResponse(l.svcCtx.Config.OSS)
	if err != nil {
		return nil, err
	}
	client, err := oss.New(l.svcCtx.Config.OSS.Pint, response.Credentials.AccessKeyId, response.Credentials.AccessKeySecret, oss.SecurityToken(response.Credentials.SecurityToken))
	if err != nil {
		return nil, err
	}
	// 获取存储空间
	bucket, err := client.Bucket(l.svcCtx.Config.OSS.Bucket)
	Filename := uuid + ".sql"
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}

	today := l.svcCtx.Config.Name + time.Now().Format("20060102") // 格式化为年月日
	objectKey := today + "/" + uuid + "." + "sql"
	// 检查文件夹是否存在，不存在则创建
	isExist, err := bucket.IsObjectExist(today + "/")
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}
	if !isExist {
		err := bucket.PutObject(today+"/", strings.NewReader(""))
		if err != nil {
			fmt.Println("Error:", err)
			return nil, err
		}
	}
	err = bucket.PutObjectFromFile(objectKey, Filename)
	if err != nil {
		fmt.Println("Error:", err)
		return nil, err
	}

	//fmt.Println(objectKey)
	// 生成永久有效的访问链接
	signedURL, err := bucket.SignURL(objectKey, oss.HTTPGet, 31536000000)
	if err != nil {
		fmt.Println(err.Error())
		return nil, err
	}
	t := time.Now()
	sysFile := model.SysFile{
		CreateTime: &t,
		UUID:       uuid,
		Name:       Filename,
		Suffix:     ".sql",
		Path:       signedURL,
	}
	err = l.svcCtx.DB.Create(&sysFile).Error
	if err != nil {
		return nil, err
	}
	utils.DellFile(sysFile.Name)
	return &pb.Emp{}, nil
}

func exportAllTablesToSQL(db *gorm.DB, name string) error {
	file, err := os.Create(name + ".sql")
	if err != nil {
		return err
	}
	_, err = file.WriteString(fmt.Sprintf("SET NAMES utf8mb4;\n"))
	if err != nil {
		return err
	}
	_, err = file.WriteString(fmt.Sprintf("SET FOREIGN_KEY_CHECKS = 0;\n"))
	if err != nil {
		return err
	}
	defer func(file *os.File) {
		err := file.Close()
		logx.Infof("执行关闭文件流")
		if err != nil {
			return
		}
	}(file)

	var tables []string
	db.Raw("SHOW TABLES").Scan(&tables)

	for _, table := range tables {
		err := exportTableStructure(db, file, table)
		if err != nil {
			return err
		}
		_, err = file.WriteString(fmt.Sprintf("BEGIN;\n"))
		if err != nil {
			return err
		}
		err = exportTableToSQL(db, file, table)
		if err != nil {
			return err
		}
		_, err = file.WriteString(fmt.Sprintf("COMMIT;\n"))
		if err != nil {
			return err
		}
	}
	return nil
}
func exportTableStructure(db *gorm.DB, file *os.File, table string) error {
	var createTableSQL string
	err := db.Raw(fmt.Sprintf("SHOW CREATE TABLE %s", table)).Row().Scan(&table, &createTableSQL)
	if err != nil {
		return err
	}
	_, err = file.WriteString(fmt.Sprintf("-- Table structure for %s\n", table))
	if err != nil {
		return err
	}

	_, err = file.WriteString(fmt.Sprintf("%s;\n\n", createTableSQL))
	if err != nil {
		return err
	}

	return nil
}
func exportTableToSQL(db *gorm.DB, file *os.File, table string) error {
	var rows *sql.Rows
	var err error
	rows, err = db.Raw(fmt.Sprintf("SELECT * FROM %s", table)).Rows()
	if err != nil {
		return err
	}
	defer rows.Close()

	columns, err := rows.Columns()
	if err != nil {
		return err
	}

	values := make([]interface{}, len(columns))
	valuePtrs := make([]interface{}, len(columns))
	for rows.Next() {
		for i := range columns {
			valuePtrs[i] = &values[i]
		}

		rows.Scan(valuePtrs...)
		sprintf := fmt.Sprintf("INSERT INTO `%s` (", table)
		for i, col := range columns {
			if i > 0 {
				sprintf += ", "
			}
			sprintf += "`" + col + "`"
		}
		sprintf += ") VALUES ("
		for i, val := range values {
			if i > 0 {
				sprintf += ", "
			}
			switch v := val.(type) {
			case nil:
				sprintf += "NULL"
			case int64:
				sprintf += fmt.Sprintf("%d", v)
			case float64:
				sprintf += fmt.Sprintf("%f", v)
			case bool:
				if v {
					sprintf += "TRUE"
				} else {
					sprintf += "FALSE"
				}
			case []byte:
				sprintf += fmt.Sprintf("'%s'", string(v))
			case string:
				sprintf += fmt.Sprintf("'%s'", v)
			case time.Time:
				times := v.Format("2006-01-02 15:04:05.000")
				sprintf += fmt.Sprintf("'%s'", times)
			default:
				sprintf += fmt.Sprintf("'%s'", v)
			}
		}
		sprintf += ");\n"
		_, err := file.WriteString(sprintf)
		if err != nil {
			return err
		}
	}
	return nil
}
